package test; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.util.ArrayList; import java.util.List; import java.util.Properties; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.DefaultServlet; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import com.github.kmkt.util.WSImageServlet; public class WSImageServletTest { private static final String PROPERTY_FILE = "imageserver.properties"; private static final int DEFAULT_WEBPORT = 8080; // Web ポート番号 private static final String DEFAULT_WSPATH = "/ws"; /** * @param args */ public static void main(String[] args) { try { if (args.length < 2) { System.out.println("Image 出力サンプルサーバ"); System.out.println(); System.out.println("USAGE A : WSImageServletTest [-p <port>] (duration) (jpg) (jpg) ..."); System.out.println("USAGE B : WSImageServletTest [-p <port>] (duration) (lst)"); System.out.println("port : ポート番号"); System.out.println("duration : フレーム間隔 (ms)"); System.out.println("jpg : 送出するJPEGファイル 複数指定時は先頭から順に送出される"); System.out.println("lst : 送出するJPEGファイルのリスト"); System.exit(-1); } // デフォルト値 int webport = DEFAULT_WEBPORT; String wspath = DEFAULT_WSPATH; // プロパティファイル読み込み File f = new File(PROPERTY_FILE); if (f.exists() && f.isFile()) { System.out.println("Load from property file. : " + PROPERTY_FILE); // Try to read property file. Properties serverprop = new Properties(); Reader freader = null; try { freader = new FileReader(PROPERTY_FILE); serverprop.load(freader); // may if (serverprop.containsKey("port")) { webport = Integer.parseInt(serverprop.getProperty("port")); } // may if (serverprop.containsKey("path")) { wspath = serverprop.getProperty("path"); } } catch (IOException e) { System.out.println("IO error at reading property file. : " + PROPERTY_FILE); System.exit(-1); } finally { if (freader != null) freader.close(); } } int arg_index = 0; // ポート指定 if (args[0].toLowerCase().equals("-p")) { webport = Integer.parseInt(args[1]); arg_index = 2; } final int duration = Integer.parseInt(args[arg_index]); arg_index++; // 読み込むファイルリストの作成 List<String> files = new ArrayList<String>(); if (args[arg_index].toLowerCase().endsWith("jpg") || args[arg_index].toLowerCase().endsWith("jpeg")) { for (; arg_index < args.length; arg_index++) { files.add(args[arg_index]); } } else { try { FileReader fr = new FileReader(args[arg_index]); BufferedReader reader = new BufferedReader(fr); String line = null; while ((line = reader.readLine()) != null) { files.add(line.trim()); } reader.close(); fr.close(); } catch (IOException e) { System.out.println("Following IOException occurred. Ignore this file."); e.printStackTrace(); System.exit(-1); } } // 画像ファイルの読み込み final List<byte[]> frames = new ArrayList<byte[]>(files.size()); List<String> loaded_files = new ArrayList<String>(files.size()); for (String file : files) { System.out.print("Loading " + file + " ... "); try { FileInputStream fi = new FileInputStream(file); ByteArrayOutputStream bo = new ByteArrayOutputStream(); int ch = 0; while ((ch = fi.read()) != -1) { bo.write(ch); } fi.close(); bo.close(); byte[] frame = bo.toByteArray(); if (frame[0] == (byte) 0xff && frame[1] == (byte) 0xd8 && // SOI frame[frame.length-2] == (byte) 0xff && frame[frame.length-1] == (byte) 0xd9) { // EOI frames.add(frame); loaded_files.add(file); System.out.println("OK"); } else { System.out.println("Invalid JPEG file format. Ignore this file."); } } catch (IOException e) { System.out.println("Following IOException occurred. Ignore this file."); e.printStackTrace(); } } if (loaded_files.size() == 0) { System.out.println("No avaleble JPEG."); System.exit(-1); } System.out.println("Duration (ms) : " + duration); System.out.println("JPEG frames :"); int i=0; for (String file : loaded_files) { System.out.printf(" %2d %s%n", i, file); i++; } // init Jetty Server server = new Server(webport); server.setStopAtShutdown(true); ServletContextHandler root = new ServletContextHandler(server, "/", ServletContextHandler.SESSIONS); // set default web servlet and document root. root.setResourceBase("./"); root.setInitParameter("org.eclipse.jetty.servlet.Default.dirAllowed", "false"); root.addServlet(DefaultServlet.class, "/*"); // MJPEGのセットアップ final WSImageServlet servlet = new WSImageServlet(); ServletHolder wsh = new ServletHolder(servlet); root.addServlet(wsh, wspath); // set callback when receive JPEG frame Thread t = new Thread(new Runnable() { @Override public void run() { try { int frame = 0; long next_time = System.currentTimeMillis() + duration; while (true) { servlet.pourFrame(frames.get(frame)); // Servlet 側でフレームが取り出されるまでブロック long now = System.currentTimeMillis(); frame++; if (frames.size() == frame) { frame = 0; } if (now < next_time) { // 次フレーム開始時刻まで待機 Thread.sleep(next_time - now); // 次々フレーム開始時刻 next_time += duration; } else { // 遅延したのでウエイト無しで次フレーム while (next_time < now) { next_time += duration; } } } } catch (InterruptedException e) { e.printStackTrace(); } } }); t.setDaemon(true); t.start(); // Jettyサーバ起動 server.start(); System.out.println("Start web server at port : " + webport); System.out.println("WebSocket path : " + wspath); // コマンド入力待ち BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); while (true) { System.out.print("Input Command >"); String line = reader.readLine(); // バックグラウンド動作対策 if (line == null) { Thread.sleep(1000); continue; } if ("".equals(line.trim())) continue; String[] cmds = line.split("\\s+"); if ("bye".equals(cmds[0])) { // bye : 終了 break; } } if (server != null) { // Jettyサーバ停止 server.stop(); server.join(); } } catch (Exception e) { e.printStackTrace(); } } }